home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2001 December / pcwk12201b.iso / Wersje pelne i specjalne / Winamp 2.77 i 3.0beta / wasabi-sdk_beta1.exe / jnetlib / httpget.cpp < prev    next >
C/C++ Source or Header  |  2001-10-08  |  11KB  |  472 lines

  1. /*
  2.  
  3.   Nullsoft WASABI Source File License
  4.  
  5.   Copyright 1999-2001 Nullsoft, Inc.
  6.  
  7.     This software is provided 'as-is', without any express or implied
  8.     warranty.  In no event will the authors be held liable for any damages
  9.     arising from the use of this software.
  10.  
  11.     Permission is granted to anyone to use this software for any purpose,
  12.     including commercial applications, and to alter it and redistribute it
  13.     freely, subject to the following restrictions:
  14.  
  15.     1. The origin of this software must not be misrepresented; you must not
  16.        claim that you wrote the original software. If you use this software
  17.        in a product, an acknowledgment in the product documentation would be
  18.        appreciated but is not required.
  19.     2. Altered source versions must be plainly marked as such, and must not be
  20.        misrepresented as being the original software.
  21.     3. This notice may not be removed or altered from any source distribution.
  22.  
  23.  
  24.   Brennan Underwood
  25.   brennan@nullsoft.com
  26.  
  27. */
  28.  
  29. /*
  30. ** JNetLib
  31. ** Copyright (C) 2000-2001 Nullsoft, Inc.
  32. ** Author: Justin Frankel
  33. ** File: httpget.cpp - JNL HTTP GET implementation
  34. ** License: see jnetlib.h
  35. */
  36.  
  37. #include "netinc.h"
  38. #include "util.h"
  39. #include "httpget.h"
  40.  
  41.  
  42. JNL_HTTPGet::JNL_HTTPGet(JNL_AsyncDNS *dns, int recvbufsize, char *proxy)
  43. {
  44.   m_recvbufsize=recvbufsize;
  45.   m_dns=dns;
  46.   m_con=NULL;
  47.   m_http_proxylpinfo=0;
  48.   m_http_proxyhost=0;
  49.   m_http_proxyport=0;
  50.   if (proxy && *proxy)
  51.   {
  52.     char *p=(char*)malloc(strlen(proxy)+1);
  53.     if (p) 
  54.     {
  55.       char *r=NULL;
  56.       strcpy(p,proxy);
  57.       do_parse_url(p,&m_http_proxyhost,&m_http_proxyport,&r,&m_http_proxylpinfo);
  58.       free(r);
  59.       free(p);
  60.     }
  61.   }
  62.   m_sendheaders=NULL;
  63.   reinit();
  64. }
  65.  
  66. void JNL_HTTPGet::reinit()
  67. {
  68.   m_errstr=0;
  69.   m_recvheaders=NULL;
  70.   m_recvheaders_size=0;
  71.   m_http_state=0;
  72.   m_http_port=0;
  73.   m_http_url=0;
  74.   m_reply=0;
  75.   m_http_host=m_http_lpinfo=m_http_request=NULL;
  76. }
  77.  
  78. void JNL_HTTPGet::deinit()
  79. {
  80.   delete m_con;
  81.   free(m_recvheaders);
  82.  
  83.   free(m_http_url);
  84.   free(m_http_host);
  85.   free(m_http_lpinfo);
  86.   free(m_http_request);
  87.   free(m_errstr);
  88.   free(m_reply);
  89.   reinit();
  90. }
  91.  
  92. JNL_HTTPGet::~JNL_HTTPGet()
  93. {
  94.   deinit();
  95.   free(m_sendheaders);
  96.   free(m_http_proxylpinfo);
  97.   free(m_http_proxyhost);
  98.  
  99. }
  100.  
  101.  
  102. void JNL_HTTPGet::addheader(const char *header)
  103. {
  104.   if (strstr(header,"\r") || strstr(header,"\n")) return;
  105.   if (!m_sendheaders)
  106.   {
  107.     m_sendheaders=(char*)malloc(strlen(header)+3);
  108.     if (m_sendheaders) 
  109.     {
  110.       strcpy(m_sendheaders,header);
  111.       strcat(m_sendheaders,"\r\n");
  112.     }
  113.   }
  114.   else
  115.   {
  116.     char *t=(char*)malloc(strlen(header)+strlen(m_sendheaders)+1+2);
  117.     if (t)
  118.     {
  119.       strcpy(t,m_sendheaders);
  120.       strcat(t,header);
  121.       strcat(t,"\r\n");
  122.       free(m_sendheaders);
  123.       m_sendheaders=t;
  124.     }
  125.   }
  126. }
  127.  
  128. void JNL_HTTPGet::do_encode_mimestr(char *in, char *out)
  129. {
  130.   char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  131.   int shift = 0;
  132.   int accum = 0;
  133.  
  134.   while (*in)
  135.   {
  136.     if (*in)
  137.     {
  138.       accum <<= 8;
  139.       shift += 8;
  140.       accum |= *in++;
  141.     }
  142.     while ( shift >= 6 )
  143.     {
  144.       shift -= 6;
  145.       *out++ = alphabet[(accum >> shift) & 0x3F];
  146.     }
  147.   }
  148.   if (shift == 4)
  149.   {
  150.     *out++ = alphabet[(accum & 0xF)<<2];
  151.     *out++='=';  
  152.   }
  153.   else if (shift == 2)
  154.   {
  155.     *out++ = alphabet[(accum & 0x3)<<4];
  156.     *out++='=';  
  157.     *out++='=';  
  158.   }
  159.  
  160.   *out++=0;
  161. }
  162.  
  163.  
  164. void JNL_HTTPGet::connect(const char *url)
  165. {
  166.   deinit();
  167.   m_http_url=(char*)malloc(strlen(url)+1);
  168.   strcpy(m_http_url,url);
  169.   do_parse_url(m_http_url,&m_http_host,&m_http_port,&m_http_request, &m_http_lpinfo);
  170.   strcpy(m_http_url,url);
  171.   if (!m_http_host || !m_http_host[0] || !m_http_port)
  172.   {
  173.     m_http_state=-1;
  174.     seterrstr("invalid URL");
  175.     return;
  176.   }
  177.  
  178.   int sendbufferlen=0;
  179.  
  180.   if (!m_http_proxyhost || !m_http_proxyhost[0])
  181.   {
  182.     sendbufferlen += 4 /* GET */ + strlen(m_http_request) + 9 /* HTTP/1.0 */ + 2;
  183.   }
  184.   else
  185.   {
  186.     sendbufferlen += 4 /* GET */ + strlen(m_http_url) + 9 /* HTTP/1.0 */ + 2;
  187.     if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
  188.     {
  189.       sendbufferlen+=58+strlen(m_http_proxylpinfo)*2; // being safe here
  190.     }
  191.   }
  192.   sendbufferlen += 5 /* Host: */ + strlen(m_http_host) + 2;
  193.  
  194.   if (m_http_lpinfo&&m_http_lpinfo[0])
  195.   {
  196.     sendbufferlen+=46+strlen(m_http_lpinfo)*2; // being safe here
  197.   }
  198.  
  199.   if (m_sendheaders) sendbufferlen+=strlen(m_sendheaders);
  200.  
  201.   char *str=(char*)malloc(sendbufferlen+1024);
  202.   if (!str)
  203.   {
  204.     seterrstr("error allocating memory");
  205.     m_http_state=-1;    
  206.   }
  207.  
  208.   if (!m_http_proxyhost || !m_http_proxyhost[0])
  209.   {
  210.     wsprintf(str,"GET %s HTTP/1.0\r\n",m_http_request);
  211.   }
  212.   else
  213.   {
  214.     wsprintf(str,"GET %s HTTP/1.0\r\n",m_http_url);
  215.   }
  216.  
  217.   wsprintf(str+strlen(str),"Host:%s\r\n",m_http_host);
  218.  
  219.   if (m_http_lpinfo&&m_http_lpinfo[0])
  220.   {
  221.     strcat(str,"Authorization: Basic ");
  222.     do_encode_mimestr(m_http_lpinfo,str+strlen(str));
  223.     strcat(str,"\r\n");
  224.   }
  225.   if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
  226.   {
  227.     strcat(str,"Proxy-Authorization: Basic ");
  228.     do_encode_mimestr(m_http_proxylpinfo,str+strlen(str));
  229.     strcat(str,"\r\n");
  230.   }
  231.  
  232.   if (m_sendheaders) strcat(str,m_sendheaders);
  233.   strcat(str,"\r\n");
  234.  
  235.   int a=m_recvbufsize;
  236.   if (a < 4096) a=4096;
  237.   m_con=new JNL_Connection(m_dns,strlen(str)+4,a);
  238.   if (m_con)
  239.   {
  240.     if (!m_http_proxyhost || !m_http_proxyhost[0])
  241.     {
  242.       m_con->connect(m_http_host,m_http_port);
  243.     }
  244.     else
  245.     {
  246.       m_con->connect(m_http_proxyhost,m_http_proxyport);
  247.     }
  248.     m_con->send_string(str);
  249.   }
  250.   else
  251.   {
  252.     m_http_state=-1;
  253.     seterrstr("could not create connection object");
  254.   }
  255.   free(str);
  256.  
  257. }
  258.  
  259. void JNL_HTTPGet::do_parse_url(char *url, char **host, int *port, char **req, char **lp)
  260. {
  261.   char *p,*np;
  262.   free(*host); *host=0;
  263.   free(*req); *req=0;
  264.   free(*lp); *lp=0;
  265.  
  266.   if (strstr(url,"://")) np=p=strstr(url,"://")+3;
  267.   else np=p=url;
  268.   while (*np != '/' && *np) np++;
  269.   if (*np)
  270.   {
  271.     *req=(char*)malloc(strlen(np)+1);
  272.     if (*req) strcpy(*req,np);
  273.     *np++=0;
  274.   } 
  275.   else 
  276.   {
  277.     *req=(char*)malloc(2);
  278.     if (*req) strcpy(*req,"/");
  279.   }
  280.  
  281.   np=p;
  282.   while (*np != '@' && *np) np++;
  283.   if (*np)
  284.   {
  285.     *np++=0;
  286.     *lp=(char*)malloc(strlen(p)+1);
  287.     if (*lp) strcpy(*lp,p);
  288.     p=np;
  289.   }
  290.   else 
  291.   {
  292.     *lp=(char*)malloc(1);
  293.     if (*lp) strcpy(*lp,"");
  294.   }
  295.   np=p;
  296.   while (*np != ':' && *np) np++;
  297.   if (*np)
  298.   {
  299.     *np++=0;
  300.     *port=atoi(np);
  301.   } else *port=80;
  302.   *host=(char*)malloc(strlen(p)+1);
  303.   if (*host) strcpy(*host,p);
  304. }
  305.  
  306.  
  307. char *JNL_HTTPGet::getallheaders()
  308. { // double null terminated, null delimited list
  309.   if (m_recvheaders) return m_recvheaders;
  310.   else return "\0\0";
  311. }
  312.  
  313. char *JNL_HTTPGet::getheader(char *headername)
  314. {
  315.   char *ret=NULL;
  316.   if (strlen(headername)<1||!m_recvheaders) return NULL;
  317.   char *buf=(char*)malloc(strlen(headername)+2);
  318.   strcpy(buf,headername);
  319.   if (buf[strlen(buf)-1]!=':') strcat(buf,":");
  320.   char *p=m_recvheaders;
  321.   while (*p)
  322.   {
  323.     if (!strnicmp(buf,p,strlen(buf)))
  324.     {
  325.       ret=p+strlen(buf);
  326.       while (*ret == ' ') ret++;
  327.       break;
  328.     }
  329.     p+=strlen(p)+1;
  330.   }
  331.   free(buf);
  332.   return ret;
  333. }
  334.  
  335. int JNL_HTTPGet::run()
  336. {
  337.   int cnt=0;
  338.   if (m_http_state==-1||!m_con) return -1; // error
  339.  
  340.  
  341. run_again:
  342.   m_con->run();
  343.  
  344.   if (m_con->get_state()==JNL_Connection::STATE_ERROR)
  345.   {
  346.     seterrstr(m_con->get_errstr());
  347.     return -1;
  348.   }
  349.   if (m_con->get_state()==JNL_Connection::STATE_CLOSED) return 1;
  350.  
  351.   if (m_http_state==0) // connected, waiting for reply
  352.   {
  353.     if (m_con->recv_lines_available()>0)
  354.     {
  355.       char buf[4096];
  356.       m_con->recv_line(buf,4095);
  357.       buf[4095]=0;
  358.       m_reply=(char*)malloc(strlen(buf)+1);
  359.       strcpy(m_reply,buf);
  360.  
  361.       if (strstr(buf,"200")) m_http_state=2; // proceed to read headers normally
  362.       else if (strstr(buf,"301") || strstr(buf,"302")) 
  363.       {
  364.         m_http_state=1; // redirect city
  365.       }
  366.       else 
  367.       {
  368.         seterrstr(buf);
  369.         m_http_state=-1;
  370.         return -1;
  371.       }
  372.       cnt=0;
  373.     }
  374.     else if (!cnt++) goto run_again;
  375.   }
  376.   if (m_http_state == 1) // redirect
  377.   {
  378.     while (m_con->recv_lines_available() > 0)
  379.     {
  380.       char buf[4096];
  381.       m_con->recv_line(buf,4096);
  382.       if (!buf[0])  
  383.       {
  384.         m_http_state=-1;
  385.         return -1;
  386.       }
  387.       if (!strnicmp(buf,"Location:",9))
  388.       {
  389.         char *p=buf+9; while (*p== ' ') p++;
  390.         if (*p)
  391.         {
  392.           connect(p);
  393.           return 0;
  394.         }
  395.       }
  396.     }
  397.   }
  398.   if (m_http_state==2)
  399.   {
  400.     if (!cnt++ && m_con->recv_lines_available() < 1) goto run_again;
  401.     while (m_con->recv_lines_available() > 0)
  402.     {
  403.       char buf[4096];
  404.       m_con->recv_line(buf,4096);
  405.       if (!buf[0]) { m_http_state=3; break; }
  406.       if (!m_recvheaders)
  407.       {
  408.         m_recvheaders_size=strlen(buf)+1;
  409.         m_recvheaders=(char*)malloc(m_recvheaders_size+1);
  410.         if (m_recvheaders)
  411.         {
  412.           strcpy(m_recvheaders,buf);
  413.           m_recvheaders[m_recvheaders_size]=0;
  414.         }
  415.       }
  416.       else
  417.       {
  418.         int oldsize=m_recvheaders_size;
  419.         m_recvheaders_size+=strlen(buf)+1;
  420.         char *n=(char*)malloc(m_recvheaders_size+1);
  421.         if (n)
  422.         {
  423.           memcpy(n,m_recvheaders,oldsize);
  424.           strcpy(n+oldsize,buf);
  425.           n[m_recvheaders_size]=0;
  426.           free(m_recvheaders);
  427.           m_recvheaders=n;
  428.         }
  429.       }
  430.     }
  431.   }
  432.   if (m_http_state==3)
  433.   {
  434.   }
  435.   return 0;
  436. }
  437.  
  438. int JNL_HTTPGet::get_status() // returns 0 if connecting, 1 if reading headers, 
  439.                     // 2 if reading content, -1 if error.
  440. {
  441.   if (m_http_state < 0) return -1;
  442.   if (m_http_state < 2) return 0;
  443.   if (m_http_state == 2) return 1;
  444.   if (m_http_state == 3) return 2;
  445.   return -1;
  446. }
  447.  
  448. int JNL_HTTPGet::getreplycode()// returns 0 if none yet, otherwise returns http reply code.
  449. {
  450.   if (!m_reply) return 0;
  451.   char *p=m_reply;
  452.   while (*p && *p != ' ') p++; // skip over HTTP/x.x
  453.   if (!*p) return 0;
  454.   return atoi(++p);
  455. }
  456.  
  457. int JNL_HTTPGet::bytes_available()
  458. {
  459.   if (m_con && m_http_state==3) return m_con->recv_bytes_available();
  460.   return 0;
  461. }
  462. int JNL_HTTPGet::get_bytes(char *buf, int len)
  463. {
  464.   if (m_con && m_http_state==3) return m_con->recv_bytes(buf,len);
  465.   return 0;
  466. }
  467. int JNL_HTTPGet::peek_bytes(char *buf, int len)
  468. {
  469.   if (m_con && m_http_state==3) return m_con->peek_bytes(buf,len);
  470.   return 0;
  471. }
  472.